﻿using System;
using System.Linq;
using System.Collections.Generic;

using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;

using Ah.Testudin.Engine.Graphics.Scenes;

namespace Ah.Testudin.Engine.Input
{
    public class FreeMovementController
    {
        #region Private Member Variables

        private const float KEYBOARD_SENSITIVITY = .1f;

        private readonly float ROTATION_SENSITIVITY = MathHelper.ToRadians(1);

        private readonly ISceneNode _sceneNode;

        #endregion

        #region Constructors

        public FreeMovementController(ISceneNode sceneNode)
        {
            if (sceneNode == null)
            {
                throw new ArgumentNullException("sceneNode");
            }

            _sceneNode = sceneNode;
        }

        #endregion

        #region Methods

        public void Update()
        {
            KeyboardState kbState = Keyboard.GetState();

            IEnumerable<Keys> pressedKeys = kbState.GetPressedKeys();

            if (pressedKeys.Contains(Keys.Left))
            {
                if (pressedKeys.Contains(Keys.LeftShift))
                {
                    // Yaw Left

                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Matrix rotation = Matrix.CreateFromAxisAngle(
                        transform.Up,
                        ROTATION_SENSITIVITY);

                    Matrix newTransform = 
                        transform *
                        rotation;

                    newTransform.Translation = transform.Translation;

                    _sceneNode.Properties.ToWorldTransform = newTransform;
                        
                }
                else
                {
                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Vector3 translation = transform.Left * KEYBOARD_SENSITIVITY;

                    _sceneNode.Properties.ToWorldTransform *= 
                        Matrix.CreateTranslation(translation);
                }
            }

            if (pressedKeys.Contains(Keys.Right))
            {
                if (pressedKeys.Contains(Keys.LeftShift))
                {
                    // Yaw Right

                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Matrix rotation = Matrix.CreateFromAxisAngle(
                        transform.Up,
                        -ROTATION_SENSITIVITY);

                    Matrix newTransform =
                        transform *
                        rotation;

                    newTransform.Translation = transform.Translation;

                    _sceneNode.Properties.ToWorldTransform = newTransform;
                }
                else
                {
                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Vector3 translation = transform.Right * KEYBOARD_SENSITIVITY;

                    _sceneNode.Properties.ToWorldTransform *=
                        Matrix.CreateTranslation(translation);
                }
            }

            if (pressedKeys.Contains(Keys.Up))
            {
                if (pressedKeys.Contains(Keys.LeftControl))
                {
                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Vector3 translation = transform.Forward * KEYBOARD_SENSITIVITY;

                    _sceneNode.Properties.ToWorldTransform *=
                        Matrix.CreateTranslation(translation);
                }
                else if (pressedKeys.Contains(Keys.LeftShift))
                {
                    // Pitch Up

                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Matrix rotation = Matrix.CreateFromAxisAngle(
                        transform.Right,
                        ROTATION_SENSITIVITY);

                    Matrix newTransform =
                        transform *
                        rotation;

                    newTransform.Translation = transform.Translation;

                    _sceneNode.Properties.ToWorldTransform = newTransform;
                }
                else
                {
                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Vector3 translation = transform.Up * KEYBOARD_SENSITIVITY;

                    _sceneNode.Properties.ToWorldTransform *=
                        Matrix.CreateTranslation(translation);
                }
            }

            if (pressedKeys.Contains(Keys.Down))
            {
                if (pressedKeys.Contains(Keys.LeftControl))
                {
                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Vector3 translation = transform.Backward * KEYBOARD_SENSITIVITY;

                    _sceneNode.Properties.ToWorldTransform *=
                        Matrix.CreateTranslation(translation);
                }
                else if (pressedKeys.Contains(Keys.LeftShift))
                {
                    // Pitch Down

                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Matrix rotation = Matrix.CreateFromAxisAngle(
                        transform.Right,
                        -ROTATION_SENSITIVITY);

                    Matrix newTransform =
                        transform *
                        rotation;

                    newTransform.Translation = transform.Translation;

                    _sceneNode.Properties.ToWorldTransform = newTransform;
                }
                else
                {
                    Matrix transform = _sceneNode.Properties.ToWorldTransform;

                    Vector3 translation = transform.Down * KEYBOARD_SENSITIVITY;

                    _sceneNode.Properties.ToWorldTransform *=
                        Matrix.CreateTranslation(translation);
                }
            }
        }

        #endregion
    }
}
